{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8d8f05a0-0ec5-419a-8887-c8507de9f867",
   "metadata": {},
   "source": [
    "# The Bermuda Triangle"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea42d70d-64e1-41f3-854d-7256453af2e8",
   "metadata": {},
   "source": [
    "## ipywidgets\n",
    "\n",
    "Here are the import statements for the interactive widgets:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "fabc2f7d-10ae-4e52-8474-93c56959baa9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import FloatSlider, IntSlider, interact"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "849a36e9-a55c-4a39-ab39-2a207385df1c",
   "metadata": {},
   "source": [
    "## matplotlib\n",
    "\n",
    "Here's the code that plots the triangle, which you'll use in the following examples:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6b3de8c8-6635-490a-9e71-5a3c7d2e0624",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.style.use(\"seaborn\")\n",
    "\n",
    "\n",
    "def draw(\n",
    "    vertices,\n",
    "    xlim=(-90, 20),\n",
    "    ylim=(-20, 50),\n",
    "    fill=\"cornflowerblue\",\n",
    "    stroke=\"royalblue\",\n",
    "    letters=False,\n",
    "):\n",
    "    plt.xlim(xlim)\n",
    "    plt.ylim(ylim)\n",
    "    plt.gca().set_aspect(\"equal\", adjustable=\"box\")\n",
    "    x = [vertex.real for vertex in vertices]\n",
    "    y = [vertex.imag for vertex in vertices]\n",
    "    plt.plot(x, y, \"o\", color=stroke)\n",
    "    plt.gca().add_patch(\n",
    "        plt.Polygon(\n",
    "            list(zip(x, y, strict=False)),\n",
    "            facecolor=fill,\n",
    "            edgecolor=stroke,\n",
    "            alpha=0.5,\n",
    "            lw=2,\n",
    "        )\n",
    "    )\n",
    "    if letters:\n",
    "        for i, vertex in enumerate(vertices):\n",
    "            plt.text(\n",
    "                vertex.real + 1,\n",
    "                vertex.imag + 1,\n",
    "                chr(65 + i),\n",
    "                color=stroke,\n",
    "                fontsize=16,\n",
    "            )\n",
    "    plt.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf2e4cc4-59b5-4f92-add9-3ab2262147c4",
   "metadata": {},
   "source": [
    "## Complex Numbers\n",
    "\n",
    "Define the region with **complex numbers**, whose real part represents the **longitude**, while the imaginary part represents the **latitude** of a city. Ignore the curvature of Earth, assuming the coordinates were already projected from spherical to rectangular:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "03282c06-8864-41c0-bd39-4f10515a8387",
   "metadata": {},
   "outputs": [],
   "source": [
    "miami_fl = complex(-80.191788, 25.761681)\n",
    "san_juan = complex(-66.105721, 18.466333)\n",
    "hamilton = complex(-64.78303, 32.2949)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbf10f02-e5bf-4892-bae0-27cd882fd9cb",
   "metadata": {},
   "source": [
    "Now, you can draw your triangle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c1fc279d-5a8e-47c5-b52f-cf01c26f84fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x396 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "triangle = miami_fl, san_juan, hamilton\n",
    "draw(triangle)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3630b69f-9657-4944-9d70-f51755283f4d",
   "metadata": {},
   "source": [
    "## Translation\n",
    "\n",
    "Align the **geometric center** of the triangle with the coordinate system's origin by applying an appropriate **translation**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b5c15ce2-5390-4aa8-8d0e-2bee2a93deec",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x396 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "geometric_center = sum(triangle) / 3\n",
    "centered_triangle = [vertex - geometric_center for vertex in triangle]\n",
    "draw(centered_triangle)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e7a014a-f999-4514-92ba-4a724c253088",
   "metadata": {},
   "source": [
    "This triangle looks the same as before, but the coordinates of its vertices have shifted.\n",
    "\n",
    "You can play around with a custom translation below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "825d607d-1286-4bf4-936e-d433b08e76f4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b9c1cf1393f8488fb45bb4c770308981",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=0, description='xoffset', max=20, min=-20), IntSlider(value=0, descripti…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "@interact(\n",
    "    xoffset=IntSlider(min=-20, max=20, value=0, step=1),\n",
    "    yoffset=IntSlider(min=-20, max=20, value=0, step=1),\n",
    ")\n",
    "def translate(xoffset, yoffset):\n",
    "    offset = complex(xoffset, yoffset)\n",
    "    scaled_triangle = [vertex + offset for vertex in centered_triangle]\n",
    "    draw(scaled_triangle)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5fbaf020-8ea9-432d-b5ed-eb50a51c8bfc",
   "metadata": {},
   "source": [
    "## Flipping\n",
    "\n",
    "To flip a complex number around an axis, take the **negative** of the relevant component or calculate the **complex conjugate** for the vertical symmetry:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1f2330f8-8324-4df4-996d-381139fbf6fc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ac69bcf4af274a2ba829ff87cef2f511",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(Checkbox(value=False, description='horizontally'), Checkbox(value=False, description='ve…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def flip_horizontally(z: complex) -> complex:\n",
    "    return complex(-z.real, z.imag)\n",
    "\n",
    "\n",
    "def flip_vertically(z: complex) -> complex:\n",
    "    return z.conjugate()  # Alternatively: complex(z.real, -z.imag)\n",
    "\n",
    "\n",
    "@interact(horizontally=False, vertically=False)\n",
    "def flip(horizontally, vertically):\n",
    "    flipped_triangle = centered_triangle\n",
    "    if horizontally:\n",
    "        flipped_triangle = [\n",
    "            flip_horizontally(vertex) for vertex in flipped_triangle\n",
    "        ]\n",
    "    if vertically:\n",
    "        flipped_triangle = [\n",
    "            flip_vertically(vertex) for vertex in flipped_triangle\n",
    "        ]\n",
    "    lim = (-20, 20)\n",
    "    draw(flipped_triangle, xlim=lim, ylim=lim, letters=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7907e6fd-3e22-4025-840f-c2627195b8eb",
   "metadata": {},
   "source": [
    "## Scaling\n",
    "\n",
    "Multiply every vertex by a **real number** to stretch the triangle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b4459aa4-b6f9-4a3a-b7bf-809dcc9c0864",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "361625647f97461bba690149cb38250e",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=1.0, description='size', max=5.0, min=0.5, step=0.5), Output()), _dom_…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "@interact(size=FloatSlider(min=0.5, max=5, value=1, step=0.5))\n",
    "def scale(size):\n",
    "    scaled_triangle = [size * vertex for vertex in centered_triangle]\n",
    "    draw(scaled_triangle)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8fcc2809-4483-41f5-b1f0-615f1b98c9ba",
   "metadata": {},
   "source": [
    "## Rotation\n",
    "\n",
    "Multiplying the triangle by the **imaginary unit** (`1j`) once has the effect of rotating it 90° counterclockwise around the coordinate system's origin. If you continue doing that, you'll arrive where you began:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "023c6d7d-dc56-452d-9ea3-6b27a79963a9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2c80157752704b9a9817b3468c53fde9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=90, description='angle', max=360), Output()), _dom_classes=('widget-inte…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def rotate(z: complex, degrees: float) -> complex:\n",
    "    return z * 1j ** (degrees / 90)\n",
    "\n",
    "\n",
    "@interact(angle=IntSlider(min=0, max=360, value=90, step=1))\n",
    "def show_rotate(angle):\n",
    "    plt.gca().add_patch(\n",
    "        plt.Circle((0, 0), 85, lw=1, edgecolor=\"silver\", facecolor=\"None\")\n",
    "    )\n",
    "    lim = (-100, 100)\n",
    "    rotated_triangle = [rotate(vertex, angle) for vertex in triangle]\n",
    "    draw(triangle, xlim=lim, ylim=lim, letters=True)\n",
    "    draw(\n",
    "        rotated_triangle,\n",
    "        xlim=lim,\n",
    "        ylim=lim,\n",
    "        fill=\"firebrick\",\n",
    "        stroke=\"maroon\",\n",
    "        letters=True,\n",
    "    )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
